package pcloud.server.datastore;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import pcloud.server.Logger;

public class ClientDataStore
{
	private static Properties clients = null;
	private static Map<String, ClientTaskList> taskMap = null;
	private String id;
	private String datastoreRootPath;
	private String clientsFileFullPath;
	static final String CLIENTS_FILE_NAME = "clients.properties";
	
	public ClientDataStore(String id, String rootPath)
	{
		this.id = id;
		this.datastoreRootPath = rootPath+"/datastore";
		this.clientsFileFullPath = datastoreRootPath + "/" + CLIENTS_FILE_NAME;
	}

	public String getClientName(String id)
	{
		return getClients().getProperty(id);
	}

	public boolean hasClient(String id)
	{
		return getClients().containsKey(id);
	}

	// public ClientTaskList getClientTasks(String id)
	// {
	// return getTaskMap().get(id);
	// }

	public int updateTask(String path, String action)
	{
		String syncAction = getSyncAction(action);
		Map<String, ClientTaskList> clientTaskMap = getTaskMap();
		Logger.log("\tpath:"+path+", action: "+action+", syncAction:"+syncAction);

		
		// 对于那些无需其他终端同步的操作, 只要更新自身的任务列表就可以了
		if ("NULL".equals(syncAction)) {
			ClientTaskList taskList = clientTaskMap.get(this.id);
			Logger.log("\t---Remove task---");
			taskList.removeTask(path, action);
			return 1;
		}

		// 对于需要其他终端同步的操作, 更新所有终端的任务列表
		int count = 0;
		Logger.log("\t---Update task---");
		for (Entry<String, ClientTaskList> clientEntry : clientTaskMap
				.entrySet()) {
			String id = clientEntry.getKey();
			ClientTaskList taskList = clientEntry.getValue();
			Logger.log("\t Client id: " + id + ", task count: "
					+ taskList.size());
			if (id.equals(this.id)) {
				Logger.log("\t try to remove task, path: [" + path
						+ "], action: " + action);
				taskList.removeTask(path, action);
			} else {
				Logger.log("\t try to update task, path: [" + path
						+ "], action: " + syncAction);
				taskList.updateTask(path, syncAction);
			}
			count++;
		}

		return count;
	}

	private String getSyncAction(String action)
	{
		return "DELE".equals(action) ? "DELE" : 
				"STOR".equals(action) ? "RETR" : 
				"APPE".equals(action) ? "RETR" : 
				"STOU".equals(action) ? "RETR" : 
				"RNTO".equals(action) ? "RNTO" :
				"MKD".equals(action) ? "MKD" :
				"RMD".equals(action) ? "RMD" :
					"NULL";
	}

	private Map<String, ClientTaskList> getTaskMap()
	{
		if (taskMap == null) {
			taskMap = new HashMap<String, ClientTaskList>();
			Properties clients = getClients();
			for (Object key : clients.keySet()) {
				String id = key.toString();
				taskMap.put(id, new PropertyFileTaskList(id, datastoreRootPath));
			}
		}
		return taskMap;
	}

	private Properties getClients()
	{
		if (clients == null) {
			clients = new Properties();
			try {
				System.out.println("get clients");
				File dataStoreRootFolder = new File(
						this.datastoreRootPath);
				if (!dataStoreRootFolder.exists()){
					dataStoreRootFolder.mkdirs();
				}
				
				File clientsFile = new File(
						this.clientsFileFullPath);
				if (clientsFile.exists()) {
					clientsFile.createNewFile();
				}
				
				InputStream in = new BufferedInputStream(new FileInputStream(
						this.clientsFileFullPath));
				clients.load(in);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return clients;
	}

	public boolean createClient(String clientId)
	{
		return createClient(clientId, clientId);
	}

	public boolean createClient(String clientId, String clientName)
	{
		Properties clients = getClients();
		clients.put(clientId, clientName);
		try {
			OutputStream out = new BufferedOutputStream(new FileOutputStream(
					this.clientsFileFullPath));
			clients.store(out, "Clients");
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}//
		return true;
	}

}
